package cn.wizzer.app.web.commons.core;

import cn.wizzer.app.sys.modules.services.SysParamService;
import cn.wizzer.app.web.commons.ext.websocket.main.action.BaseNettyAction;
import cn.wizzer.app.web.commons.ext.websocket.main.filter.BaseNettyFilter;
import cn.wizzer.app.web.commons.ext.websocket.main.start.NettyWebSocketChannelInitializer;
import cn.wizzer.app.web.commons.ext.websocket.main.start.TcpServer;
import cn.wizzer.app.web.commons.ext.websocket.main.start.TcpServerStarter;
import cn.wizzer.app.web.commons.utils.RedisUtil;
import com.alibaba.dubbo.config.annotation.Reference;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.nutz.boot.NbApp;
import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.Ioc;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.annotation.ChainBy;
import org.nutz.mvc.annotation.Modules;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Created by wizzer on 2018/4/4.
 */
@IocBean(create = "init", depose = "depose")
@Modules(packages = "cn.wizzer")
@ChainBy(args = "chain/nutzwk-mvc-chain.json")
public class WebApiMainLauncher {

    private static final Log log = Logs.get();
    @Inject("java:$conf.get('tcp.port')")
    private int tcpPort;

    @Inject("java:$conf.get('boss.thread.count')")
    private int bossCount;

    @Inject("java:$conf.get('worker.thread.count')")
    private int workerCount;

    @Inject("java:$conf.get('so.keepalive')")
    private boolean keepAlive;

    @Inject("java:$conf.get('so.backlog')")
    private int backlog;

    @Inject("refer:$ioc")
    private Ioc ioc;

    @Inject
    private PropertiesProxy conf;

    @Inject
    @Reference
    private SysParamService sysParamService;

    public static void main(String[] args) throws Exception {
        NbApp nb = new NbApp().setArgs(args).setPrintProcDoc(true);
        nb.getAppContext().setMainPackage("cn.wizzer");
        nb.run();
        System.out.println("started");
    }

    public void init() throws Exception {
        //redisUtil
        RedisUtil.init(ioc.get(RedisService.class));
        //启动websocket
        ioc.addBean("tcpSocketAddress", new InetSocketAddress(tcpPort));
        TcpServerStarter.instance().setTcpServer(ioc.get(TcpServer.class)).start();
        //通过获取实例方式使ioc容器加载beans
        for (BaseNettyAction instance : BaseNettyAction.instances()) {
            System.out.println("netty-websocket action bean:"+ioc.get(instance.getClass()));
        }
        for (BaseNettyFilter instance : BaseNettyFilter.instances()) {
            System.out.println("netty-websocket filter bean:"+ioc.get(instance.getClass()));
        }
    }

    @IocBean(name = "tcpChannelOptions")
    public Map<ChannelOption<?>, Object> tcpChannelOptions() {
        Map<ChannelOption<?>, Object> options = new HashMap<ChannelOption<?>, Object>();
        options.put(ChannelOption.SO_KEEPALIVE, keepAlive);
        options.put(ChannelOption.SO_BACKLOG, backlog);
        return options;
    }

    @Inject
    private NettyWebSocketChannelInitializer nettyWebSocketChannelInitializer;

    @IocBean(name = "serverBootstrap")
    public ServerBootstrap bootstrap() {
        ServerBootstrap b = new ServerBootstrap();
        b.group(bossGroup(), workerGroup())
                .channel(NioServerSocketChannel.class)
                .handler(new LoggingHandler(LogLevel.DEBUG))
                .childHandler(nettyWebSocketChannelInitializer);
        Map<ChannelOption<?>, Object> tcpChannelOptions = tcpChannelOptions();
        Set<ChannelOption<?>> keySet = tcpChannelOptions.keySet();
        for (@SuppressWarnings("rawtypes") ChannelOption option : keySet) {
            b.option(option, tcpChannelOptions.get(option));
        }
        return b;
    }

    @IocBean(name = "bossGroup", depose = "shutdownGracefully")
    public NioEventLoopGroup bossGroup() {
        return new NioEventLoopGroup(bossCount);
    }

    @IocBean(name = "workerGroup", depose = "shutdownGracefully")
    public NioEventLoopGroup workerGroup() {
        return new NioEventLoopGroup(workerCount);
    }


    public void depose() {

    }
}
